<?php

namespace addons\groupon\library\traits\model\order;

use addons\groupon\exception\Exception;
use addons\groupon\model\ScoreGoodsSkuPrice;
use addons\groupon\model\Goods;
use addons\groupon\model\User;
use addons\groupon\model\UserAddress;
use addons\groupon\model\UserCoupons;
use addons\groupon\model\Dispatch;
use think\Cache;
use think\Db;

trait OrderOperCreate
{
    
    /**
     * 获取请求参数，初始化，并设置默认值
     *
     * @param array $params
     * @return array
     */
    public static function preParams($params) {
        extract($params);

        $store_id = $store_id ?? 0;

        return compact(
            "goods_list",
            "store_id",
            "coupons_id",
            "from"
        );
    }
    
    /**
     * 下单前检测，商品状态，活动状态，必要的选择项等
     *
     * @param array $params，请求参数
     * @return array
     */
    public static function preCheck($params, $calc_type) {
        $user = User::info();

        // 获取请求参数
        extract(self::preParams($params));

        $activity_type = '';
        $new_goods_list = [];
        $activity_discounts = [];
        foreach ($goods_list as $key => $buyinfo) {
            // 最少购买一件
            $buyinfo['goods_num'] = intval($buyinfo['goods_num']) < 1 ? 1 : intval($buyinfo['goods_num']);

            $sku_price_id = $buyinfo['sku_price_id'];


            $detail = Goods::getGoodsDetail($buyinfo['goods_id']);

            // 有活动，并且还未被拼接过
            if (isset($detail['activity_type']) && $detail['activity_type'] && strpos($activity_type, $detail['activity_type']) === false) {
                $activity_type .= $detail['activity_type'] . ',';       // 记录所有活动信息
            }

            // 商品参与的有折扣活动
            if (isset($detail['activity_discounts']) && $detail['activity_discounts']) {
                $activity_discounts = array_merge($activity_discounts, $detail['activity_discounts']);
            }

            $sku_prices = $detail['sku_price'];
            foreach ($sku_prices as $key => $sku_price) {
                if ($sku_price['id'] == $sku_price_id) {
                    $detail->current_sku_price = $sku_price;
                    break;
                }
            }

            if (!$detail || $detail->status === 'down') {
                new Exception('商品不存在或已下架');
            }

            if (!isset($detail->current_sku_price) || !$detail->current_sku_price) {
                new Exception('商品规格不存在');
            }

            $buyinfo['dispatch_type'] = 'selfetch';     // 配送方式全是自提

            // 组装 商品详情
            $buyinfo['detail'] = $detail;
            $new_goods_list[] = $buyinfo;

            if ($detail->current_sku_price['stock'] < $buyinfo['goods_num']) {
                // 不够自己买
                new Exception('商品库存不足');
            }
        }

        if (!count($new_goods_list)) {
            new Exception('请选择要购买的商品');
        }

        return [
            $new_goods_list,
            $activity_discounts,
            $activity_type
        ];
    }


    /**
     * 计算订单各种费用
     *
     * @param array $new_goods_list
     * @return array
     */
    public static function preCalcAmount($params, $new_goods_list) {
        // 获取请求参数
        extract(self::preParams($params));

        $goods_original_amount = 0;         // 商品原始总价
        $goods_amount = 0;                  // 商品总价
        $total_amount = 0;                  // 订单总金额
        $total_fee = 0;                     // 支付金额 
        $discount_fee = 0;                  // 折扣总金额
        $coupon_fee = 0;                    // 优惠券金额

        // 计算商品金额
        foreach ($new_goods_list as $key => $buyinfo) {
            $detail = $buyinfo['detail'];

            // 当前商品原始总价
            $current_goods_original_amount = bcmul($detail->original_price, $buyinfo['goods_num'], 2);
            $goods_original_amount = bcadd($goods_original_amount, $current_goods_original_amount, 2);

            // 当前商品现在总价
            $current_goods_amount = bcmul($detail->current_sku_price->price, $buyinfo['goods_num'], 2);
            $goods_amount = bcadd($goods_amount, $current_goods_amount, 2);

            // 用户选择的门店
            $current_store_id = $store_id ?? 0;

            // 将计算好的属性记录下来，插入订单 item 表使用
            $new_goods_list[$key]['goods_original_amount'] = $current_goods_original_amount;
            $new_goods_list[$key]['goods_amount'] = $current_goods_amount;
            $new_goods_list[$key]['store_id'] = $current_store_id;
            $new_goods_list[$key]['activity_type'] = '';
            $new_goods_list[$key]['discount_fee'] = 0;  // 初始化每个商品分配到的优惠
        }

        return [
            $new_goods_list,                // 新的商品列表
            $goods_original_amount,         // 商品原始总价
            $goods_amount,                  // 商品总价
        ];
    }


    /**
     * 计算商品的优惠，优惠促销 和 优惠券
     *
     * @param array $new_goods_list
     * @param array $activity_discounts
     * @param string $activity_type
     * @return array
     */
    public static function preCalcDiscount(
        $params, 
        $new_goods_list,
        $activity_type,
        $activity_discounts, 
        $goods_amount
    ) {
        // 获取请求参数
        extract(self::preParams($params));

        $activity_discount_infos = [];      // 参与的所有促销活动信息
        $activity_discount_money = 0;       // 促销活动金额
        $activity_gift_money = 0;           // 赠送总额
        $activity_gift_coupon_ids = '';           // 赠送的优惠券 ids
        $activity_type = '';                // 参与的活动

        $discounts = [];
        // 过滤重复活动
        foreach ($activity_discounts as $activity_discount) {
            if (!isset($discounts[$activity_discount['id']])){
                $discounts[$activity_discount['id']] = $activity_discount;
            }
        }

        // 将购买的商品，按照活动分类
        foreach ($new_goods_list as $new_goods) {
            $detail = $new_goods['detail'];
            unset($new_goods['detail']);
            if (isset($detail['activity_discounts']) && $detail['activity_discounts']) {
                foreach ($detail['activity_discounts'] as $ad) {
                    $discounts[$ad['id']]['goods'][] = $new_goods;
                }
            }
        }

        // 计算各个活动是否满足
        foreach($discounts as $key => $discount) {
            if (!isset($discount['goods'])) {
                // 活动没有商品，直接 next
                continue;
            }

            $discount_total_money = 0;          // 该活动中商品的总价
            $discount_total_num = 0;            // 该活动商品总件数
            $goodsIds = [];                     // 该活动中所有的商品 id

            // 活动中的商品总金额，总件数，所有商品 id
            foreach ($discount['goods'] as $goods) {
                $discount_total_money = bcadd($discount_total_money, $goods['goods_amount'], 2);
                $discount_total_num = bcadd($discount_total_num, $goods['goods_num'], 2);
                $goodsIds[] = $goods['goods_id'];
            }

            $rules = $discount['rules'];
            // 是按金额，还是按件数比较
            $compareif = $rules['type'] == 'num' ? 'discount_total_num' : 'discount_total_money';
            
            if (in_array($discount['type'], ['full_reduce', 'full_discount', 'full_gift'])) {
                // 将规则按照从大到校排列,优先比较是否满足最大规则
                $rules_discounts = isset($rules['discounts']) && $rules['discounts'] ? array_reverse($rules['discounts']) : [];    // 数组反转

                // 满减， 满折多个规则从大到小匹配最优惠
                foreach ($rules_discounts as $d) {
                    if (${$compareif} < $d['full']) {
                        // 不满足条件，接着循环下个规则
                        continue;
                    }

                    $current_activity_discount_money = 0;   // 优惠金额， full_gift 为 0
                    $current_activity_gift_money = 0;   // 赠送金额， full_gift 时候存在
                    // 满足优惠
                    if ($discount['type'] == 'full_reduce') {
                        // 满减
                        $current_activity_discount_money = (isset($d['discount']) && $d['discount']) ? $d['discount'] : 0;
                    } else if ($discount['type'] == 'full_discount') {
                        // 满折
                        $dis = bcdiv($d['discount'], 10, 3);        // 保留三位小数，转化折扣
                        $dis = $dis > 1 ? 1 : ($dis < 0 ? 0 : $dis);    // 定义边界 0 - 1
                        $activity_dis = 1 - $dis;
                        $current_activity_discount_money = round(bcmul($discount_total_money, $activity_dis, 3), 2);       // 计算折扣金额,四舍五入
                    } else if ($discount['type'] == 'full_gift') {
                        // 满赠
                        $current_activity_gift_money = (isset($d['total']) && $d['total']) ? $d['total'] : 0;

                        // 拼接需要赠送的优惠券 ids
                        $activity_gift_coupon_ids .= $d['coupons_ids'] . ',';
                    }

                    // 记录该活动的一些统计信息
                    $activity_discount_infos[] = [
                        'activity_id' => $discount['id'],                           // 活动id
                        'activity_title' => $discount['title'],                     // 活动标题
                        'activity_type' => $discount['type'],                       // 活动类型
                        'activity_discount_money' => $current_activity_discount_money,      // 优惠金额， full_gift 为 0
                        'activity_gift_money' => $current_activity_gift_money,      // 赠送金额， full_gift 时候存在
                        'rule_type' => $rules['type'],                              // 满多少元|还是满多少件
                        'event' => $rules['event'] ?? '',                           // 满赠的时候才会有，赠送时机
                        'discount_rule' => $d,                                      // 满足的那条规则
                        'goods_ids' => join(',', $goodsIds)                         // 这个活动包含的这次购买的商品
                    ];

                    // 累加促销活动总计优惠金额
                    $activity_discount_money = bcadd($activity_discount_money, $current_activity_discount_money, 2);

                    // 累加促销活动总计赠送金额
                    $activity_gift_money = bcadd($activity_gift_money, $current_activity_gift_money, 2);

                    // 拼接参与的活动类型，只拼接没拼接过的
                    if (strpos($activity_type, $discount['type']) === false) {
                        $activity_type .= $discount['type'] . ',';
                    }
                    break;
                }
            }
        }

        // 多活动拼接去掉多余的 ,
        $activity_type = rtrim($activity_type, ',');
        $activity_gift_coupon_ids = rtrim($activity_gift_coupon_ids, ',');

        // 计算优惠券费用
        $user_coupons = null;
        $coupon_money = 0;
        if ($coupons_id) {
            // 查询传来的优惠券 id 是否可用
            $coupons = self::coupons($params, $goods_amount);

            $current_coupons = null;        // 当前所选优惠券
            foreach ($coupons as $key => $coupon) {
                if ($coupon['user_coupons_id'] == $coupons_id) {
                    $current_coupons = $coupon;
                    break;
                }
            }

            if ($current_coupons) {
                $coupon_money = $current_coupons->amount;     // 金额在 coupons 表存着
                $user_coupons = UserCoupons::where('id', $coupons_id)->find();        // 用户优惠券
            } else {
                new Exception('优惠券不可用');
            }
        }

        if ($activity_discount_infos) {
            // 将每个商品对应的 activity_type 放入 new_goods_list
            foreach($activity_discount_infos as $info) {
                $goodsIds = explode(',', $info['goods_ids']);

                foreach ($goodsIds as $goods_id) {
                    // 寻找商品id 等于 $goods_id 的所有商品，存在同一个商品，购买多个规格的情况
                    foreach ($new_goods_list as $g_k => $goods) {
                        if ($goods['goods_id'] == $goods_id) {
                            if (strpos($new_goods_list[$g_k]['activity_type'], $info['activity_type']) === false) {
                                $new_goods_list[$g_k]['activity_type'] .= $info['activity_type'] . ',';
                            }
                        }
                    }
                }
            }

            // 去除多余的 ,
            foreach($new_goods_list as $key => $goods) {
                $new_goods_list[$key]['activity_type'] = rtrim($new_goods_list[$key]['activity_type'], ',');
            }
        }

        return [
            $new_goods_list,
            $activity_discount_infos,
            $activity_discount_money,
            $activity_gift_money,
            $activity_gift_coupon_ids,
            $activity_type,
            $user_coupons,
            $coupon_money
        ];
    }


    /**
     * 计算订单费用
     *
     * @param array $new_goods_list
     * @param float $goods_amount
     * @param float $origin_dispatch_amount 原始运费
     * @param float $dispatch_amount
     * @param int $score_amount
     * @param float $activity_discount_money
     * @param float $coupon_money
     * @return array
     */
    public static function preCalcOrder(
        $new_goods_list,
        $goods_amount,
        $activity_discount_infos,
        $activity_discount_money,
        $coupon_money
    ) {
        $total_amount = $goods_amount;
        $coupon_fee = $coupon_money;
        $discount_fee = bcadd($coupon_money, $activity_discount_money, 2);
        $total_fee = bcsub($total_amount, $discount_fee, 2);
        $total_fee = $total_fee < 0 ? 0 : $total_fee;

        $new_goods_list = self::calcDiscountFee(
            $new_goods_list,
            $goods_amount,
            $discount_fee,
            $activity_discount_infos,
            $activity_discount_money
        );

        return [
            $new_goods_list,
            $total_amount,
            $discount_fee,
            $total_fee,
            $coupon_fee,
        ];
    }



    /**
     * 处理返回结果
     *
     * @param float $goods_original_amount
     * @param float $goods_amount
     * @param float $total_amount
     * @param float $total_fee
     * @param float $discount_fee
     * @param float $coupon_fee
     * @param float $activity_discount_money
     * @param string $activity_type
     * @param array $new_goods_list
     * @param array $activity_discount_infos
     * @param array $user_coupons
     * @param string $calc_type
     * @return array
     */
    public static function preReturnParams(
        $goods_original_amount,
        $goods_amount,
        $total_amount,
        $total_fee,
        $discount_fee,
        $coupon_fee,
        $activity_discount_money,
        $activity_gift_money,
        $activity_gift_coupon_ids,
        $activity_type,
        $new_goods_list,
        $activity_discount_infos,
        $user_coupons,
        $calc_type      // 计算方式
    ) {
        // 需要处理小数点的数据
        $result = compact(
            "goods_original_amount",
            "goods_amount",
            "total_amount",
            "total_fee",
            "discount_fee",
            "coupon_fee",
            "activity_discount_money",
            "activity_gift_money"
        );

        // 处理小数点保留两位小数
        foreach ($result as $key => $amount) {
            $result[$key] = number_format($amount, 2, '.', '');
        }

        // 合并不需要处理小数点的
        $result = array_merge($result, compact(
            "activity_type",
            "new_goods_list",
            "activity_discount_infos",
            "activity_gift_coupon_ids"
        ));

        // 如果是下单，合并 优惠券， 收货地址
        if ($calc_type == 'create') {
            $result = array_merge($result, compact(
                "user_coupons"
            ));
        }

        return $result;
    }


    /**
     * 计算每个商品在优惠券，活动中应该分配到的优惠
     *
     * @param array $new_goods_list
     * @param float $goods_amount
     * @param float $discount_fee
     * @param array $activity_discount_infos
     * @param float $activity_discount_money
     * @param float $dispatch_discount_money
     * @param array $free_shipping_goods_ids
     * @return array
     */
    private static function calcDiscountFee(
        $new_goods_list,
        $goods_amount,
        $discount_fee,
        $activity_discount_infos,
        $activity_discount_money
    ) {

        if (floatval($activity_discount_money)) {
            foreach ($activity_discount_infos as $key => $info) {
                if ($info['activity_type'] == 'full_gift') {
                    // 满赠跳过
                    continue;
                }
                $current_discount_goods_ids = explode(',', $info['goods_ids']);
                $current_total_goods_amount = 0; // 当前活动的商品总金额
                foreach ($new_goods_list as $key => $buyinfo) {
                    if (in_array($buyinfo['goods_id'], $current_discount_goods_ids)) {
                        $current_total_goods_amount = bcadd($current_total_goods_amount, $buyinfo['goods_amount'], 2);
                    }
                }

                // 计算当前活动商品，每个商品应该分配到的优惠金额
                foreach ($new_goods_list as $key => $buyinfo) {
                    if (!in_array($buyinfo['goods_id'], $current_discount_goods_ids)) {
                        // 不是当前活动的商品，跳过
                        continue;
                    }

                    $scale = 0;                             // 按照商品价格和总价计算每个 item 的比例
                    if (floatval($current_total_goods_amount)) {          // 字符串 0.00 是 true, 这里转下类型在判断
                        $scale = bcdiv($buyinfo['goods_amount'], $current_total_goods_amount, 6);
                    }

                    // 每个商品分配到的折扣
                    $current_activity_discount_fee = round(bcmul($info['activity_discount_money'], $scale, 3), 2);
                    $new_goods_list[$key]['discount_fee'] = bcadd($new_goods_list[$key]['discount_fee'], $current_activity_discount_fee, 2);
                }
            }
        }

        // 剩余要加权平均分配的优惠
        $last_discount_money = bcsub($discount_fee, $activity_discount_money, 2);
        // 计算每个商品分配到的优惠券的优惠金额，顺便计算出来 pay_price 的金额
        foreach ($new_goods_list as $key => $buyinfo) {
            $scale = 0;                             // 按照商品价格和总价计算每个 item 的比例
            if (floatval($goods_amount)) {          // 字符串 0.00 是 true, 这里转下类型在判断
                $scale = bcdiv($buyinfo['goods_amount'], $goods_amount, 6);
            }

            // 每个商品分配到的折扣
            $current_discount_fee = round(bcmul($last_discount_money, $scale, 3), 2);
            $new_goods_list[$key]['discount_fee'] = bcadd($new_goods_list[$key]['discount_fee'], $current_discount_fee, 2);
            // 每个商品除了运费之后分配的支付金额
            $new_goods_list[$key]['pay_price'] = bcsub($buyinfo['goods_amount'], $new_goods_list[$key]['discount_fee'], 2);
        }

        return $new_goods_list;
    }
}
